package api

import (
	"fmt"
	"github.com/rclone/rclone/lib/version"
	"io"
	"strconv"
	"time"
)

// Error describes a B2 error response
//type Error struct {
//	Status  int    `json:"status"`    // The numeric HTTP status code. Always matches the status in the HTTP response.
//	Code    string `json:"code"`      // A single-identifier code that identifies the error.
//	Message string `json:"code_text"` // A human-readable message, in English, saying what went wrong.
//}

// Error describes a Iharbor error response

type Error struct {
	Code       int    `json:"code" :"code"` // The numeric HTTP status code. Always matches the status in the HTTP response.
	CodeString string `json:"code" :"code_string"`
	Data       struct {
		Name string `json:"name" :"name"`
	} `json:"data" :"data"` // A single-identifier code that identifies the error.
	Message string `json:"code_text" :"message"` // A human-readable message, in English, saying what went wrong.
}

//func (e Error) Error() string {
//	return fmt.Sprintf("%s (%d %s)", e.Message, e.Status, e.Code)
//}

func (e Error) Error() string {
	return fmt.Sprintf("%s (%d %s)", e.Message, e.Data, e.Code)
}

// Bucket describes a Iharbor bucket
// {
//  "code": 200,
//  "bucket": {
//    "id": 7,
//    "name": "test",
//    "user": {
//      "id": 3,
//      "username": "wanghuang@cnic.cn"
//    },
//    "created_time": "2022-03-23T10:58:15.238662+08:00",
//    "access_permission": "私有",
//    "ftp_enable": true,
//    "ftp_password": "666666",
//    "ftp_ro_password": "6779704d15",
//    "remarks": ""
//  }
//}
type Bucket struct {
	ID   int    `json:"id"`   // bucket ID
	Name string `json:"name"` // bucket Name
	//AccountID string `json:"accountId"` // user ID
	AccountID struct {
		ID       int    `json:"id"`
		UserName string `json:"username"`
	} `json:"user"` // user ID

	Type        string `json:"access_permission"` // iharbor  -- > 作为桶访问权限  私有
	FtpStatus   bool   `json:"ftp_enable"`        // ftp 访问状态  false 关闭  true 为 开启
	Remarks     string `json:"remarks"`
	CreatedTime string `json:"created_time"`
}

// ListBucketsRequest is parameters for b2_list_buckets call
type ListBucketsRequest struct {
	AccountID struct {
		ID       int    `json:"id"`
		UserName string `json:"username"`
	} `json:"user"` // user ID
	BucketID    int      `json:"id,omitempty"`                // When specified, the result will be a list containing just this bucket.
	BucketName  string   `json:"name,omitempty"`              // When specified, the result will be a list containing just this bucket.
	BucketTypes []string `json:"access_permission,omitempty"` // If present, B2 will use it as a filter for bucket types returned in the list buckets response.
	FtpStatus   bool     `json:"ftp_enable"`                  // ftp 访问状态  false 关闭  true 为 开启
}

// ListBucketsResponse is as returned from the b2_list_buckets call
type ListBucketsResponse struct {
	Count int    `json:"count"` // 桶的数量
	Next  string `json:"next"`
	Page  struct {
		Current int `json:"current"`
		Final   int `json:"final"`
	} `json:"page"`
	Previous string   `json:"previous"`
	Buckets  []Bucket `json:"buckets"`
}

type InfoPerson struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

type AuthorizeAccountRequest struct {
	Data *InfoPerson `json:"data"`
}

type AuthorizeAccountResponse struct {
	Token struct {
		Key string `json:"key"` // 身份验证时的key  例如Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b；

	} `json:"token"`
	APIURL string `json:"apiurl"`
}

// 存留token
type Token struct {
	Token string `json:"token"`
}

// Timestamp is a UTC time when this file was uploaded. It is a base
// 10 number of milliseconds since midnight, January 1, 1970 UTC. This
// fits in a 64 bit integer such as the type "long" in the programming
// language Java. It is intended to be compatible with Java's time
// long. For example, it can be passed directly into the java call
// Date.setTime(long time).
type Timestamp time.Time

// File is info about a file
type File struct {
	Name                  string            `json:"name"`              // 文件或目录名称
	AllFilePath           string            `json:"na"`                // "na": "sacva/client.ovpn", # 全路径文件或目录名称
	IsFileOrDir           bool              `json:"fod"`               // 是文件还是目录  false 是目录  true 为 文件
	Size                  int64             `json:"si"`                // The number of bytes in the file.
	UploadTimestamp       string            `json:"ult"`               // This is a UTC time when this file was uploaded.
	ReviseFileTime        string            `json:"upt"`               // 修改文件时间
	DownloadFileFrequency int               `json:"dlc"`               // 下载次数 目录不算
	DownLoadUrl           string            `json:"download_url"`      // 下载地址
	PermissionToUse       string            `json:"access_permission"` // 使用权限
	MD5                   string            `json:"md5"`               // The MD5 of the bytes stored in the file.
	ContentType           string            `json:"contentType"`       // The MIME type of the file.
	Info                  map[string]string `json:"fileInfo"`
}

// ListFileNamesRequest is as passed to b2_list_file_names or b2_list_file_versions
type ListFileNamesRequest struct {
	BucketName    string `json:"bucket_name"` // required - The bucket to look for file names in.
	DirPath       string `json:"dirpath"`
	StartFileName string `json:"startFileName,omitempty"` // optional - The first file name to return. If there is a file with this name, it will be returned in the list. If not, the first file name after this the first one after this name.
	StartFileID   string `json:"startFileId,omitempty"`   // optional - What to pass in to startFileId for the next search to continue where this one left off.
	// Defaults to NULL. Folder names will also be returned.
	//The delimiter character will be used to "break" file names into folders.
}

// ListFileNamesResponse is as received from /api/v1/dir/{bucket_name}/{dirpath}/
type ListFileNamesResponse struct {
	Files        []File  `json:"files"` // An array of objects, each one describing one file.
	FileCount    int     `json:"count"`
	NextFileName *string `json:"nextFileName"` // What to pass in to startFileName for the next search to continue where this one left off, or null if there are no more files.
	NextFileID   *string `json:"nextFileId"`   // What to pass in to startFileId for the next search to continue where this one left off, or null if there are no more files.
}

// AddVersion adds the timestamp as a version string into the filename passed in.
func (t Timestamp) AddVersion(remote string) string {
	return version.Add(remote, time.Time(t))
}

// RemoveVersion removes the timestamp from a filename as a version string.
//
// It returns the new file name and a timestamp, or the old filename
// and a zero timestamp.
func RemoveVersion(remote string) (t Timestamp, newRemote string) {
	time, newRemote := version.Remove(remote)
	t = Timestamp(time)
	return
}

// IsZero returns true if the timestamp is uninitialized
func (t Timestamp) IsZero() bool {
	return time.Time(t).IsZero()
}

// Equal compares two timestamps  相等比较两个时间戳
//
// If either are !IsZero then it returns false
func (t Timestamp) Equal(s Timestamp) bool {
	if time.Time(t).IsZero() {
		return false
	}
	if time.Time(s).IsZero() {
		return false
	}
	return time.Time(t).Equal(time.Time(s))
}

// UnmarshalJSON turns JSON into a Timestamp
func (t *Timestamp) UnmarshalJSON(data []byte) error {
	timestamp, err := strconv.ParseInt(string(data), 10, 64)
	if err != nil {
		return err
	}
	*t = Timestamp(time.Unix(timestamp/1e3, (timestamp%1e3)*1e6).UTC())
	return nil
}

// TFormatTime  将 "2022-04-08T17:47:30.162485+08:00"  转换成 time.Time 格式
func TFormatTime(s string) Timestamp {
	TIME_LAYOUT := "2006-01-02T15:04:05+08:00"
	str, _ := time.Parse(TIME_LAYOUT, s)
	return Timestamp(str)
}

// CreateBucketRequest is used to create a bucket
type CreateBucketRequest struct {
	Name string `json:"name"` // 桶名称
}

// ExistBucketRequest  检查桶存在的请求
type ExistBucketRequest struct {
	BucketName string `json:"id_or_name"` // 桶的id 或 name 默认使用 name
}

// FileInfo is received from b2_upload_file, b2_get_file_info and b2_finish_large_file
type FileInfo struct {
	Code        int    `json:"code"`
	CodeString  string `json:"code"`
	Created     bool   `json:"created"`
	CodeText    string `json:"code_text"`
	ContentType string `json:"content-type"` // The MIME type of the file.
}

// DeleteBucketRequest is used to create a bucket
type DeleteBucketRequest struct {
	ID string `json:"id_or_name"`
}

type UploadPartRequest struct {
	ChunkOffset int64     `json:"chunk_offset"`
	Size        int64     `json:"chunk_size"`
	Chunk       io.Reader `json:"chunk"`
	Reset       string    `json:"reset"`
}

// UploadPartResponse is the response to Iharbor_upload_part
type UploadPartResponse struct {
	ChunkOffset int    `json:"chunk_offset"`
	Chunk       string `json:"chunk"`
	Size        int    `json:"chunk_size"`
	Created     bool   `json:"created"`
	//Code        string `json:"code"`
	//Message     string `json:"message"`
}

// 遍历目录
type TraverseDirectory struct {
	Code       int    `json:"code"`
	BucketName string `json:"bucket_name"`
	DirPath    string `json:"dir_path"`
	Files      []File `json:"files"`
	Count      int    `json:"count"`
	Next       string `json:"next"`
	Page       struct {
		Current int `json:"current"`
		Final   int `json:"final"`
	} `json:"page"`
	Previous     string  `json:"previous"`
	NextFileName *string `json:"nextFileName"` // What to pass in to startFileName for the next search to continue where this one left off, or null if there are no more files.
	NextFileID   *string `json:"nextFileId"`
}

type ListFileInfo struct {
	Name  string
	IsDir bool
	Size  int
}

// V1EmptyFileUpload v1 空文件上传
type V1EmptyFileUpload struct {
	Code     int    `json:"code"`
	CodeText string `json:"code_text"`
}

// 元数据信息
type Metadata struct {
	Code       int    `json:"code"`
	CodeText   string `json:"code_text"`
	BucketName string `json:"bucket_name"`
	DirPath    string `json:"dir_path"`
	Obj        File   `json:"obj"`
	Info       struct {
		ChunkSize int    `json:"chunk_size"`
		Size      int    `json:"size"`
		Filename  string `json:"filename"`
	} `json:"info"`
	// 剩下内容展示不写
}

type cpPart struct {
	Chunk       FileChunk // 分片
	IsCompleted bool      // upload是否完成
}

// FileChunk 文件片定义
type FileChunk struct {
	Number int    // 块序号
	Offset int64  // 块在文件中的偏移量
	Size   int64  // 块大小
	MD5    string // 块md5
}

type UploadCheckpoint struct {
	FilePath  string   // 本地文件
	ObjectKey string   // key  远程路径
	Parts     []cpPart // 本地文件的全部分片
}
